package main

import (
	"fmt"
	"net"
	"os"
	"os/signal"
	"syscall"

	"github.com/beego/beego/v2/core/logs"
	"github.com/hashicorp/consul/api"
	uuid "github.com/satori/go.uuid"
	"go.uber.org/zap"
	"google.golang.org/grpc"
	"google.golang.org/grpc/health"
	"google.golang.org/grpc/health/grpc_health_v1"

	"2106a-zg5/demo/order/order_srv/global"
	"2106a-zg5/demo/order/order_srv/hander"
	"2106a-zg5/demo/order/order_srv/initialization"
	"2106a-zg5/demo/order/order_srv/proto"
)

func main() {
	//初始化 日志信息
	initialization.Loggerssss()
	//初始化 一个 viper
	initialization.ViperSSS()
	//初始化 nacos
	initialization.NacosInit()
	//初始化 数据库
	initialization.MysqlInit()
	s := grpc.NewServer()
	proto.RegisterOrderServiceServer(s, &hander.OrderService{})
	//获得 系统空余端口号
	port, _ := GetFreePort()
	listen, err := net.Listen("tcp", fmt.Sprintf("%s:%d", global.OrderConfig.IPAddress, port))
	if err != nil {
		logs.Info("微服务 注册失败！！！")
		return
	}
	//在微服务上注册一个 健康检测机制
	grpc_health_v1.RegisterHealthServer(s, health.NewServer())

	//实例化一个consul
	cfg := api.DefaultConfig()
	//连接对象
	cfg.Address = fmt.Sprintf("%s:%d", global.OrderConfig.Consul.Host, global.OrderConfig.Consul.Port)
	//通过对象 创建一个 客户端
	client, err := api.NewClient(cfg)
	if err != nil {
		zap.S().Debug("Consul client 创建失败！！！")
		return
	}
	//生成一个 健康检测
	check := &api.AgentServiceCheck{
		//某个 微服务的 公网IP地址和端口号
		GRPC:                           fmt.Sprintf("%s:%d", global.OrderConfig.IPAddress, port),
		Timeout:                        "5s", //设置 Timeout 字段，该字段是用于指定健康检查的超时时间，这里设置为"5s"，表示5秒。
		Interval:                       "5s", //设置 Interval 字段，该字段是用于指定健康检查的间隔时间，这里设置为"5s"，表示每隔5秒进行一次健康检查。
		DeregisterCriticalServiceAfter: "10s",
	}
	//生成一个  唯一 id
	serverID := fmt.Sprintf("%s", uuid.NewV4())

	//生成一个 注册对象
	registerObj := new(api.AgentServiceRegistration)
	registerObj.Name = global.OrderConfig.Consul.Name
	registerObj.ID = serverID
	registerObj.Address = global.OrderConfig.IPAddress
	registerObj.Port = port
	registerObj.Tags = []string{"WM", "order"}
	registerObj.Check = check

	//通过客户端 去注册
	err = client.Agent().ServiceRegister(registerObj)
	if err != nil {
		zap.S().Debug("注册失败")
		return
	}

	//用协程去启动rpc服务
	go func() {
		err = s.Serve(listen)
		if err != nil {
			panic("failed to start grpc:" + err.Error())
		}
	}()
	zap.S().Info("IP地址:" + global.OrderConfig.IPAddress)
	zap.S().Info("端口号:" + fmt.Sprintf("%d", port))
	//接收终止信号
	quit := make(chan os.Signal)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	<-quit
	if err = client.Agent().ServiceDeregister(serverID); err != nil {
		zap.S().Info("注销失败")
	}
	zap.S().Info("注销成功")
}

func GetFreePort() (int, error) {
	addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
	if err != nil {
		return 0, err
	}
	l, err := net.ListenTCP("tcp", addr)
	if err != nil {
		return 0, err
	}
	defer l.Close()
	return l.Addr().(*net.TCPAddr).Port, nil
}
